#!/usr/bin/env python
# -*-*- encoding: utf-8 -*-*-
#
#
# Copyright 2007-2008 Håvard Gulldahl
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A desktop client for PicasaWeb services."""

from PyQt4 import QtCore

import gdata.photos, gdata.media
import gdata.photos.service
import os.path

if False:
    import httplib
    httplib.HTTPConnection.debuglevel=1  ## verbosely output http traffic


import atom
atom.XML_STRING_ENCODING=None # workaround bug

from picturetags import Tagreader

class PicasaWorkerThread(QtCore.QThread):
  def __init__(self, agent, *args):
    QtCore.QThread.__init__(self, *args)
    self.agent = agent

  def doGetFeed(self, uri):
    print "GetFeed:", uri
    try:
      return self.agent.photoclient.GetFeed(uri)
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      return False

class PicasaLoginThread(PicasaWorkerThread):
  def setCredentials(self, username, password):
    self.username = username
    self.password = password

  def run(self):
    print "Logging in by thread ", QtCore.QThread.currentThread()
    try:
      self.agent.photoclient.ClientLogin(self.username, self.password)
    except Exception, e:
      print e
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      self.agent.emit(QtCore.SIGNAL('loggedIn(PyQt_PyObject)'), False)
    else:
      self.agent.authenticated = True
      print "logged in"
      self.agent.emit(QtCore.SIGNAL('loggedIn(PyQt_PyObject)'), True)
    return
    self.exec_()

class PicasaGetAlbumsThread(PicasaWorkerThread):
  def setUser(self, user):
    self.user = user
  def run(self):
    try:
      albums = self.agent.photoclient.GetUserFeed(kind='album', user=self.user)
      self.agent.emit(QtCore.SIGNAL('gotAlbums(PyQt_PyObject)'), albums)
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), str(e.message))
    return
    self.exec_()

class PicasaGetPhotosThread(PicasaWorkerThread):
  def __del__(self):
    self.wait()

  def setAlbum(self, albumItem):
    self.albumItem = albumItem

  def run(self):
    print "Getting photos in thread", QtCore.QThread.currentThread()
    try:
      photos = self.doGetFeed(self.albumItem.entry.GetPhotosUri())
      self.agent.emit(QtCore.SIGNAL('gotPhotos(PyQt_PyObject,PyQt_PyObject)'), self.albumItem, photos )
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
    return
    self.exec_()
    #self.exit()


class PicasaDeleteThread(PicasaWorkerThread):
  def setItem(self, item):
    self.item = item
  def run(self):
    try:
      self.agent.photoclient.Delete(self.item.entry)
      self.agent.emit(QtCore.SIGNAL('deleted(PyQt_PyObject)'), self.item)
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
    return
    self.exec_()

class PicasaGetThumbnailThread(PicasaWorkerThread):
  def setUri(self, uri):
    self.uri = uri
  def run(self):
    try:
      data = self.agent.photoclient.GetMedia(self.uri).file_handle.read()
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      return False
    else:
      self.agent.emit(QtCore.SIGNAL('gotThumbnail(PyQt_PyObject)'), data)
    return
    self.exec_()

class PicasaGetPhotoThread(PicasaWorkerThread):
  pass

class PicasaSearchThread(PicasaWorkerThread):
  def setQuery(self, scope, query):
    self.query = query
    self.kwargs = {}
    if scope=="user":
      self.method = self.agent.photoclient.SearchUserPhotos
    elif scope=="contact":
      self.method = self.agent.photoclient.SearchContactsPhotos
    elif scope=="public":
      self.method = self.agent.photoclient.SearchCommunityPhotos
    else:
      self.method = self.agent.photoclient.SearchUserPhotos
      self.kwargs['user'] = scope

  def run(self):
    try:
      photos = self.method(self.query, **self.kwargs)
    except Exception, e:
      print e.message
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      return False
    else:
      self.agent.emit(QtCore.SIGNAL('gotSearchResult(PyQt_PyObject)'), photos )
    return
    self.exec_()


class PicasaUpdateThread(PicasaWorkerThread):
  pass
class PicasaInsertPhotoThread(PicasaWorkerThread):
  def setData(self, albumItem, **kwords):
    self.albumItem = albumItem
    self.kwords = kwords
    #print self.kwords

  def run(self):
    try:
      metadata = gdata.photos.PhotoEntry()
      metadata.title=atom.Title(text=self.kwords['title'])
      if self.kwords['summary']:
        metadata.summary = atom.Summary(text=self.kwords['summary'], summary_type='text')
      if self.kwords['keywords']:
        metadata.media.keywords = gdata.media.Keywords(text=self.kwords['keywords'])
      if self.kwords['location']:
        metadata.geo.set_location(self.kwords['location'])
      print metadata
      self.agent.photoclient.InsertPhoto(self.albumItem.entry, metadata,
        self.kwords['filename_or_handle'], self.kwords['content_type'])
      self.agent.emit(QtCore.SIGNAL('insertedPhoto()'))
      print "Uploaded successfully"
      self.agent.doGetPhotos(self.albumItem)
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      raise
    return
    self.exec_()

  def run2(self):
    try:
      self.kwords.pop('location', None)
      self.agent.photoclient.InsertPhotoSimple(self.albumItem.entry, **self.kwords)
      self.agent.emit(QtCore.SIGNAL('insertedPhoto()'))
      print "Uploaded successfully"
      self.agent.doGetPhotos(self.albumItem)
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      raise
    return
    self.exec_()

class PicasaInsertAlbumThread(PicasaWorkerThread):
  def setData(self, albumTitle, albumSummary=None):
    self.albumTitle = albumTitle
    self.albumSummary = albumSummary

  def run(self):
    try:
      self.agent.photoclient.InsertAlbum(title=self.albumTitle, summary=self.albumSummary)
      self.agent.emit(QtCore.SIGNAL('insertedAlbum()'))
      print "Added album successfully"
      self.agent.doGetAlbums()
    except Exception, e:
      self.agent.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      raise
    return
    self.exec_()



class PicasaAgent(QtCore.QObject):
  photoclient = None
  authenticated = False
  defaultFormat = 'image/jpeg'

  def __init__(self):
    QtCore.QObject.__init__(self)
    self.photoclient = gdata.photos.service.PhotosService(source='lurtgjort.no-picasapush-0.3')
    self.login = PicasaLoginThread(self)
    self.getAlbums = PicasaGetAlbumsThread(self)
    self.getPhotos = PicasaGetPhotosThread(self)
    self.delete = PicasaDeleteThread(self)
    self.getThumbnail = PicasaGetThumbnailThread(self)
    self.getPhoto = PicasaGetPhotoThread(self)
    self.search = PicasaSearchThread(self)
    self.update = PicasaUpdateThread(self)
    self.insertPhoto = PicasaInsertPhotoThread(self)
    self.insertAlbum = PicasaInsertAlbumThread(self)

  def doAbort(self):
    print 'aborting all threads!'
    for thr in (self.login, self.getAlbums, self.delete, self.getThumbnail, self.getPhoto, self.search, self.update.self.insert):
      print "thread is runing:", thr.isRunning()
      if thr.isRunning():
        thr.terminate()

  def doLogin(self, un, pw):
    self.login.setCredentials(un, pw)
    self.login.start()

  def doGetAlbums(self, user='default'):
    print "getalbums"
    self.getAlbums.setUser(user)
    self.getAlbums.start()

  def doGetPhotos(self, albumItem):
    print "doGetPhotos", albumItem
    #if self.getPhotos.isRunning():
      #print "doGetphotos already runing! abort!"
      #self.getPhotos.terminate()
    self.getPhotos.setAlbum(albumItem)
    self.getPhotos.start()

  def doGetFeed(self, uri):
    print "GetFeed:", uri
    try:
      return self.photoclient.GetFeed(uri)
    except Exception, e:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
      return False

  def doDelete(self, item):
    print "doDelete", item
    if not self.authenticated:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), 'Not logged in')
      return
    self.delete.setItem(item)
    self.delete.start()

  def doGetThumbnail(self, url):
    print "doThumbnail", url
    if self.getThumbnail.isRunning():
      print "is already running!"
      self.getThumbnail.terminate()
    self.getThumbnail.setUri(url)
    self.getThumbnail.start()

  def doInsertPhoto(self, albumItem, filename, name=None, format=None):
    print "doInsertPhoto", filename
    if not self.authenticated:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), 'Not logged in')
      return False

    try:
      fhandle = open(filename)
    except IOError, e:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), 'File does not exist: %s' % filename)
      return
    if name is None:
      name = os.path.basename(filename)
    if format is None:
      format = self.defaultFormat
    keywords = ['picasapusher',]
    tags = Tagreader(filename)
    keywords += tags.getKeywords()

    print "Inserting image", name, filename, keywords
    self.insertPhoto.setData(albumItem, title=name, summary=tags.getCaption(), filename_or_handle=fhandle, content_type=format, keywords=','.join(keywords), location=tags.getLocation())
    self.insertPhoto.start()

  def doInsertAlbum(self, albumTitle, albumSummary=None):
    if not self.authenticated:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), 'Not logged in')
      return False
    print "doInsertAlbum", albumTitle
    self.insertAlbum.setData(albumTitle, albumSummary)
    self.insertAlbum.start()

  def doSearch(self, scope, query):
    print "doSearch", scope, query
    if scope in ('user','contact') and not self.authenticated:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), 'Not logged in')
      return False

    if self.search.isRunning():
      print "aborting running search!"
      self.search.terminate()
    self.search.setQuery(scope, query)
    self.search.start()

  def doUpdatePhoto(self, entry):
    #print "doUpdatePhoto, ", entry
    try:
      newEntry = self.photoclient.UpdatePhotoMetadata(entry)
    except Exception, e:
      self.emit(QtCore.SIGNAL('error(PyQt_PyObject)'), e.message)
    else:
      self.emit(QtCore.SIGNAL('gotUpdatedPhoto(PyQt_PyObject)'), newEntry )

  def abort(self):
    print "abort!"